package com.sk.bilibili.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sk.bilibili.bean.Appraise;
import com.sk.bilibili.bean.Coin;
import com.sk.bilibili.bean.VideoSet;
import com.sk.bilibili.dto.SearchInfo;
import com.sk.bilibili.event.BiliBiliEvent;
import com.sk.bilibili.other.R;
import com.sk.bilibili.utils.BSessionUtils;
import com.sk.bilibili.utils.QueryWrapperUtils;
import com.sk.bilibili.utils.RedisUtils;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.regex.Pattern;
import org.springframework.beans.factory.annotation.Autowired;
import com.sk.bilibili.bean.Them;
import com.sk.bilibili.mapper.ThemMapper;

/**
* @author 邵康
* @date 2021/11/23 16:11
*/
@Service
public class ThemService extends ServiceImpl<ThemMapper,Them> {

    @Autowired
    private MinioService minioService;
    @Autowired
    private VideoSetService videoSetService;
    @Autowired
    private VideoService videoService;
    @Autowired
    private FollowThemService followThemService;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private PraiseService praiseService;
    @Autowired
    private CoinService coinService;
    @Autowired
    private AppraiseService appraiseService;
    private static final String SMALLCOVER_PATH="them/smallCover/%s.jpg";
    private static final Pattern SMALLCOVER_PATTERN=Pattern.compile("/(them/smallCover/.*jpg)");
    private static final String VERTICALCOVER_PATH="them/verticalCover/%s.jpg";
    private static final Pattern VERTICALCOVER_PATTERN=Pattern.compile("/(them/verticalCover/.*jpg)");

    @EventListener(condition = "event.type == 'com.sk.bilibili.service.AppraiseService.add'")
    public void handleAppraiseAdd(BiliBiliEvent<Appraise> event){
        Appraise appraise = event.getData();
        updateScore(appraise.getThemId(),appraise.getScore(),1);
    }

    @EventListener(condition = "event.type == 'com.sk.bilibili.service.AppraiseService.update'")
    public void handleAppraiseUpdate(BiliBiliEvent<Appraise> event){
        Appraise appraise = event.getData();
        Appraise old = appraiseService.getById(appraise.getId());
        updateScore(old.getThemId(),appraise.getScore()-old.getScore(),0);
    }

    @EventListener(condition = "event.type == 'com.sk.bilibili.service.CoinService.add'")
    public void handleCoinAdd(BiliBiliEvent<Coin> event){
        Coin coin = event.getData();
        if(coin.getType()!=1)return;
        changeNum("coinNum",coin.getNum(),coin.getTargetId());
    }

    public R<Void> add(Them them) {
        them.setSmallCover(minioService.add(them.getSmallCoverFile(),SMALLCOVER_PATH));
        them.setVerticalCover(minioService.add(them.getVerticalCoverFile(),VERTICALCOVER_PATH));
        save(them);
        return R.success();
    }

    public R<Void> delete(Integer id) {
        Them temp = getById(id);
        minioService.delete(temp.getSmallCover(),SMALLCOVER_PATTERN);
        minioService.delete(temp.getVerticalCover(),VERTICALCOVER_PATTERN);
        removeById(id);
        return R.success();
    }

    public R<Void> update(Them them) {
        Them temp = getById(them.getId());
        String smallCover = minioService.update(SMALLCOVER_PATH, SMALLCOVER_PATTERN, temp.getSmallCover(), them.getSmallCoverFile());
        them.setSmallCover(smallCover);
        String verticalCover = minioService.update(VERTICALCOVER_PATH, VERTICALCOVER_PATTERN, temp.getVerticalCover(), them.getVerticalCoverFile());
        temp.setVerticalCover(verticalCover);
        updateById(them);
        return R.success();
    }

    public R<IPage<Them>> page(Integer page, Integer size) {
        return R.success(page(new Page<>(page,size),null));
    }

    public R<List<Them>> getUpdate(Integer updateDay, Integer typeId) {
        List<Them> list = baseMapper.getUpdate(updateDay, typeId);
        list.forEach(this::warpThem);
        return R.success(list);
    }

    private void warpThem(Them them) {
        Integer videoSetId = them.getVideoSetId();
        them.getExtra().addExtra(videoSetService.getById(videoSetId));
        them.getExtra().put("updateNum",videoService.getNum(videoSetId));
        them.getExtra().put("latestVideo",videoService.getLatestVideo(videoSetId));
    }

    public R<List<Them>> getRank(Integer size, Integer typeId, Boolean finish) {
        List<Them> list = baseMapper.getRank(size, typeId,finish);
        list.forEach(this::warpThem);
        return R.success(list);
    }

    public IPage<Them> searchThem(SearchInfo searchInfo) {
        Page<Them> page = baseMapper.searchThem(searchInfo.page(), searchInfo);
        page.getRecords().forEach(this::warpThem);
        return page;
    }

    /**
     * 可能对应的视频集是番剧类型 但是还没有转换为番剧
     */
    public Integer getThemId(Integer videoSetId) {
        QueryWrapper<Them> queryWrapper = QueryWrapperUtils.eq("video_set_id", videoSetId);
        Them one = getOne(queryWrapper);
        if(one==null)return null;
        return one.getId();
    }

    public Them getWarpThem(Integer id) {
        Them them = getById(id);
        warpThem(them);
        int memberId = BSessionUtils.getMemberId();
        them.getExtra().put("praise",praiseService.hasPraise(memberId,1,id));
        return them;
    }

    public R<List<Them>> getRandom(Integer size, Boolean finish, Integer typeId) {
        List<Them> list=baseMapper.getRandom(size,finish,typeId);
        list.forEach(this::warpThem);
        return R.success(list);
    }

    public R<Them> getThem(Integer id) {
        // 封装基本信息
        Them them = getById(id);
        VideoSet videoSet = videoSetService.getVideoSetWithVideos(them.getVideoSetId());
        them.getExtra().addExtra(videoSet);
        int memberId = BSessionUtils.getMemberId();
        followThemService.warpFollowState(memberId,them);
        them.getExtra().put("updateNum",videoService.getNum(them.getVideoSetId()));
        them.getExtra().put("appraise",appraiseService.getAppraise(id,memberId));
        //  为了前端统一  写在这里
        videoSet.getExtra().put("praise",praiseService.hasPraise(memberId,1,id));
        videoSet.getExtra().put("coin",coinService.hasCoin(memberId,1,id));
        return R.success(them);
    }

    /**
     * @param themId  番剧Id
     * @param score   变更的分数
     * @param num     变更的数量
     */
    public void updateScore(Integer themId, Integer score, int num) {
        Them them = getById(themId);
        float sum=them.getScore()*them.getReviewNum()+score;
        num+=them.getReviewNum();
        them.setReviewNum(num);
        them.setScore(sum/num);
        updateById(them);
    }

    // 转发修改
    public void changeNum(String column, Integer num, Integer id) {
        if(column.equals("followNum")){
            redisUtils.changeNum("Them-"+id,column,num);
        }else {//若不是  follow_num  修改 其他直接 转交给videoSetService
            Them them = getById(id);
            videoSetService.changeNum(column, num, them.getVideoSetId());
        }
    }

}
